home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / archivers / xpk / xpk_source / xpkmaster / xpkmaster.c < prev    next >
C/C++ Source or Header  |  1999-06-14  |  20KB  |  691 lines

  1. #ifndef XPKMASTER_XPKMASTER_C
  2. #define XPKMASTER_XPKMASTER_C
  3.  
  4. /* Routinesheader
  5.  
  6.     Name:        xpkmaster.c
  7.     Main:        xpkmaster
  8.     Versionstring:    $VER: xpkmaster.c 1.16 (12.03.1999)
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    the main xpk functions
  12.  
  13.  1.0   09.10.96 : first real version
  14.  1.1   27.12.96 : removed 1.3 specific functions
  15.  1.2   10.01.97 : corrected XpkPack's abort
  16.  1.3   11.01.97 : corrected mem bug (reported by Laurent Kempe)
  17.  1.4   30.01.97 : hopefully fixed mem bug finally
  18.  1.5   31.01.97 : bug still occured
  19.  1.6   01.03.97 : added NoPack stuff to XpkWrite and XpkPack
  20.  1.7   24.03.97 : fixed XpkPack
  21.  1.8   25.03.97 : added AutoPasswd
  22.  1.9   28.03.97 : moved autopassword into xpkopen
  23.  1.10  01.04.97 : fixed NoPack error
  24.  1.11  19.12.97 : added xfdmaster support, made MBUG defines
  25.  1.12  09.01.98 : better passkey handling
  26.  1.13  21.02.98 : uses new style register definition
  27.  1.14  26.08.98 : lonely XpkWrite fixes
  28.  1.15  13.09.98 : added seek support, removed PP stuff
  29.  1.16  12.02.99 : added better debug output
  30. */
  31.  
  32. /**************************************************/
  33. #ifdef __MAXON__                /**/
  34.   #define MBUGDEF    ULONG maxon_bug;    /**/
  35.   #define MBUG        maxon_bug = (ULONG)    /**/
  36. #else                        /**/
  37.   #define MBUG                      /**/
  38.   #define MBUGDEF                /**/
  39. #endif                        /**/
  40. /**************************************************/
  41.  
  42. #include <proto/exec.h>
  43. #include <proto/intuition.h>
  44. #include <proto/dos.h>
  45. #include <proto/utility.h>
  46. #include <proto/xpkmaster.h>
  47. #include <proto/xfdmaster.h>
  48. #include <proto/xpksub.h>
  49. #include <exec/types.h>
  50. #include <exec/memory.h>
  51. #include <exec/tasks.h>
  52. #include <dos/dos.h>
  53. #include "xpkmaster.h"
  54. #include "texts.h"
  55.  
  56. #ifdef SUPPORT_A4
  57.   LONG XpkOpenA4NAME(struct XpkFib **xfh, struct TagItem *tags, ULONG a4);
  58.   #ifdef __SASC
  59.     #pragma libcall XpkBase XpkOpenA4NAME 036 C9803
  60.   #else
  61.     #pragma amicall(XpkBase,0x36,XpkOpenA4NAME(a0,a1,a4))
  62.   #endif
  63. #else
  64.   #define XpkOpenA4NAME XpkOpen
  65. #endif
  66.  
  67. /**************************************************************************
  68.  *
  69.  *   XpkPack() - pack a file
  70.  *
  71.  */
  72.  
  73. ASM(LONG) LIBXpkPack(REG(a0, struct TagItem *tags) A4PROTO)
  74. {
  75.   struct XpkBuffer *xbuf = 0;
  76.   STRPTR buf;
  77.   LONG totlen, res, chunklen;
  78.  
  79. #ifdef DEBUG
  80.   DebugRunTime("XpkPack");
  81. #endif
  82.  
  83.   if(!FindTagItem(XPK_PackMethod, tags))
  84.     return XPKERR_BADPARAMS;
  85.  
  86.   if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
  87.     return res;
  88.  
  89.   if((totlen = xbuf->xb_InLen) == 0xFFFFFFFF)
  90.   {
  91.     xbuf->xb_Result = XPKERR_BADPARAMS;
  92.     return XpkClose((struct XpkFib *) xbuf);
  93.   }
  94.  
  95.   CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */
  96.  
  97.   xbuf->xb_Prog.xp_Type = XPKPROG_START;
  98.   xbuf->xb_Prog.xp_ULen = totlen;
  99.   if(callprogress(xbuf))
  100.     return XpkClose((struct XpkFib *) xbuf);
  101.  
  102.   while(totlen > 0)
  103.   {
  104.     chunklen = xbuf->xb_Fib.xf_NLen;
  105.  
  106.     if(!(buf = (STRPTR) hookread(xbuf, XIO_READ, NULL, chunklen)))
  107.       break;
  108.  
  109.     if(XpkWrite((struct XpkFib *) xbuf, buf, chunklen))
  110.       break;
  111.  
  112.     totlen -= chunklen;
  113.  
  114.     xbuf->xb_Prog.xp_Type = XPKPROG_MID;    /* Progress report     */
  115.     xbuf->xb_Prog.xp_UCur += chunklen;
  116.     xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
  117.     if(callprogress(xbuf))
  118.       return XpkClose((struct XpkFib *) xbuf);
  119.   }
  120.  
  121.   if(xbuf->xb_Prog.xp_Type)
  122.   {
  123.     xbuf->xb_Prog.xp_Type = XPKPROG_END;
  124.     xbuf->xb_Prog.xp_CCur += xbuf->xb_Headers.h_LocSize;
  125.     xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ?
  126.       strings[TXT_ABORTED] : xbuf->xb_LastMsg;
  127.     callprogress(xbuf);     /* Call the hook one last time */
  128.   }
  129.  
  130.   return XpkClose((struct XpkFib *) xbuf);
  131. }
  132.  
  133. /*********************************************************************
  134.  *
  135.  * XpkUnpack - unpack a file
  136.  *
  137.  */
  138.  
  139. ASM(LONG) LIBXpkUnpack(REG(a0, struct TagItem *tags) A4PROTO)
  140. {
  141.   struct XpkBuffer *xbuf = NULL;
  142.   STRPTR pointer;
  143.   LONG len, res;
  144.  
  145. #ifdef DEBUG
  146.   DebugRunTime("XpkUnpack");
  147. #endif
  148.  
  149.   if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
  150.     return res;
  151.  
  152.   if(xbuf->xb_Flags & XMF_PACKING)
  153.   {
  154.     xbuf->xb_Result = XPKERR_BADPARAMS;
  155.     goto Abort;
  156.   }
  157.  
  158.   CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */
  159.  
  160.   xbuf->xb_Prog.xp_Type = XPKPROG_START;    /* Initialize progress */
  161.   xbuf->xb_Prog.xp_ULen = xbuf->xb_Fib.xf_ULen;
  162.   if(callprogress(xbuf))
  163.     goto Abort;
  164.  
  165.   if(!hookwrite(xbuf, XIO_TOTSIZE, NULL, xbuf->xb_Fib.xf_ULen + XPK_MARGIN))
  166.   {
  167. #ifdef DEBUG
  168.     DebugError("XpkUnpack: XIO_TOTSIZE failed");
  169. #endif
  170.     goto Abort;
  171.   }
  172.  
  173.   if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, 0, xbuf->xb_Fib.xf_NLen)))
  174.   {
  175. #ifdef DEBUG
  176.     DebugError("XpkUnpack: XIO_GETBUF failed (a)");
  177. #endif
  178.     goto Abort;
  179.   }
  180.  
  181. #ifdef DEBUG
  182.   if(xbuf->xb_Result)
  183.     DebugError("XpkUnpack: failure before unpackloop");
  184. #endif
  185.  
  186.   while((len = XpkRead((struct XpkFib *) xbuf, pointer, xbuf->xb_Fib.xf_NLen)) > 0)
  187.   {
  188.     if(!hookwrite(xbuf, XIO_WRITE, pointer, len))
  189.     {
  190. #ifdef DEBUG
  191.       DebugError("XpkUnpack: XIO_WRITE failed");
  192. #endif
  193.       goto Abort;
  194.     }
  195.  
  196.     xbuf->xb_Prog.xp_Type = XPKPROG_MID;    /* Progress report     */
  197.     xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
  198.     xbuf->xb_Prog.xp_UCur = xbuf->xb_Fib.xf_UCur;
  199.     if(callprogress(xbuf))
  200.       goto Abort;
  201.  
  202.     if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, xbuf->xb_Fib.xf_NLen)))
  203.     {
  204. #ifdef DEBUG
  205.       DebugError("XpkUnpack: XIO_GETBUF failed (b)");
  206. #endif
  207.       goto Abort;
  208.     }
  209.   }
  210.  
  211.   xbuf->xb_Result = len;
  212. #ifdef DEBUG
  213.   if(xbuf->xb_Result)
  214.     DebugError("XpkUnpack: XpkRead failed with %ld", xbuf->xb_Result);
  215. #endif
  216.  
  217.   if(xbuf->xb_Prog.xp_Type)
  218.   {
  219.     xbuf->xb_Prog.xp_Type = XPKPROG_END;
  220.     xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ? strings[TXT_ABORTED] : xbuf->xb_LastMsg;
  221.     callprogress (xbuf);    /* Call the hook one last time */
  222.   }
  223. Abort:
  224.   return XpkClose((struct XpkFib *) xbuf);
  225. }
  226.  
  227. /*********************************************************************
  228.  *
  229.  * XpkOpen - open a file for packing/unpacking
  230.  *
  231.  */
  232.  
  233. ASM(LONG) LIBXpkOpen(REG(a0, struct XpkBuffer **xbufp),
  234.     REG(a1, struct TagItem *tags) A4PROTO)
  235. {
  236. #if defined(DEBUG) && defined(SUPPORT_A4)
  237.   DebugRunTime("XpkOpen: A4 = %ld", a4);
  238. #elif defined(DEBUG)
  239.   DebugRunTime("XpkOpen");
  240. #endif
  241.   return xpkopen(xbufp, tags, 0 A4SUPP);
  242. }
  243.  
  244. /**************************************************************************
  245.  *
  246.  *   XpkExamine() - inspect a compressed file
  247.  *
  248.  */
  249.  
  250. ASM(LONG) LIBXpkExamine(REG(a0, struct XpkFib *fib),
  251.     REG(a1, struct TagItem *tags) A4PROTO)
  252. {
  253.   struct XpkBuffer *dummy;
  254.   LONG res;
  255.  
  256. #if defined(DEBUG) && defined(SUPPORT_A4)
  257.   DebugRunTime("XpkExamine: A4 = %ld", a4);
  258. #elif defined(DEBUG)
  259.   DebugRunTime("XpkExamine");
  260. #endif
  261.  
  262.   if((res = xpkopen(&dummy, tags, 1 A4SUPP)))
  263.     return res;
  264.  
  265.   CopyMem(dummy, fib, sizeof(struct XpkFib));
  266.   /* copies the entries of XpkFib
  267.      *fib = dummy->Fib works too, but calls it's own copy-function */
  268.  
  269.   return XpkClose((struct XpkFib *) dummy);
  270. }
  271.  
  272. /**************************************************************************
  273.  *
  274.  *   XpkRead() - read one chunk from a compressed file
  275.  *
  276.  */
  277.  
  278. ASM(LONG) LIBXpkRead(REG(a0, struct XpkBuffer *xbuf), REG(a1, STRPTR buf),
  279.     REG(d0, ULONG len))
  280. {
  281.   MBUGDEF
  282.  
  283. #ifdef DEBUG
  284.   DebugRunTime("XpkRead: buf %08lx, size %ld, uncrunched (%ld/%ld), crunched (%ld/%ld)", buf, len,
  285.   xbuf->xb_Fib.xf_UCur, xbuf->xb_Fib.xf_ULen, xbuf->xb_Fib.xf_CCur,xbuf->xb_Fib.xf_CLen);
  286. #endif
  287.  
  288.   if(!xbuf)
  289.     return XPKERR_NOFUNC;
  290.  
  291.   if(xbuf->xb_Flags & XMF_EOF)
  292.     return 0;
  293.  
  294.   switch(xbuf->xb_Format) 
  295.   {
  296.     /*********************** Unpack standard XPK *******************/
  297.   case XPKMODE_UPSTD:
  298.     {
  299.       struct XpkSubParams *xpar;
  300.       struct Library *XpkSubBase = xbuf->xb_SubBase;
  301.       XpkChunkHeader *lochdr = &(xbuf->xb_Headers.h_Loc);
  302.       LONG ulen, clen, rclen, lochdrsize = xbuf->xb_Headers.h_LocSize;
  303.       ULONG csum;
  304.  
  305.       if(lochdr->xch_Word.xchw_Type == XPKCHUNK_END)
  306.         return 0;
  307.  
  308.       if((MBUG hchecksum((STRPTR) lochdr, lochdrsize)))
  309.       {
  310. #ifdef DEBUG
  311.         DebugError("XpkRead: hchecksum(,%ld) failed", lochdrsize);
  312. #endif
  313.         return(xbuf->xb_Result = XPKERR_CHECKSUM);
  314.       }
  315.  
  316.       getUClen(xbuf, &ulen, &clen);
  317.       rclen = ROUNDLONG(clen);
  318.  
  319.       if(lochdr->xch_Word.xchw_Type == XPKCHUNK_RAW)
  320.       {
  321.         if(!(MBUG hookread(xbuf, XIO_READ, buf, rclen + lochdrsize)))
  322.       return xbuf->xb_Result;
  323.  
  324.         if(!(xbuf->xb_Flags & XMF_NOCRC))
  325.       if((csum=cchecksum((ULONG *) buf, rclen >>2)) != lochdr->xch_Word.xchw_CChk)
  326.       {
  327. #ifdef DEBUG
  328.         DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >> 2, csum, (ULONG) lochdr->xch_Word.xchw_CChk);
  329. #endif
  330.         return (xbuf->xb_Result = XPKERR_CHECKSUM);
  331.           }
  332.  
  333.         CopyMem(buf + rclen, lochdr, lochdrsize);
  334.       }
  335.       else if(lochdr->xch_Word.xchw_Type == XPKCHUNK_PACKED)
  336.       {
  337.         xpar = &xbuf->xb_PackParam;
  338.         if(!(xpar->xsp_InBuf = hookread(xbuf, XIO_READ, NULL, rclen + lochdrsize)))
  339.       return xbuf->xb_Result;
  340.  
  341.         if(!(xbuf->xb_Flags & XMF_NOCRC))
  342.       if((csum=cchecksum((ULONG *)xpar->xsp_InBuf, rclen >> 2)) != lochdr->xch_Word.xchw_CChk)
  343.       {
  344. #ifdef DEBUG
  345.         DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >>2 , csum, (ULONG) lochdr->xch_Word.xchw_CChk);
  346. #endif
  347.         return (xbuf->xb_Result = XPKERR_CHECKSUM);
  348.           }
  349.         xbuf->xb_Flags |= XMF_INITED;
  350.  
  351.         xpar->xsp_InLen = clen;
  352.         xpar->xsp_OutLen = ulen;
  353.         xpar->xsp_OutBuf = buf;
  354.         xpar->xsp_OutBufLen = ulen;
  355.         xpar->xsp_Number = 0;
  356.         xpar->xsp_Password = xbuf->xb_Password;
  357.         xpar->xsp_LibVersion = xbuf->xb_Headers.h_Glob.xsh_SubVrs;
  358.  
  359.         if((xbuf->xb_Result = XpksUnpackChunk(xpar)))
  360.       return xbuf->xb_Result;
  361.  
  362.         CopyMem((STRPTR) xpar->xsp_InBuf + rclen, lochdr, lochdrsize);
  363.       }
  364.       else
  365.         return (xbuf->xb_Result = XPKERR_CORRUPTPKD);
  366.  
  367.       if(updatefib(xbuf))
  368.         return xbuf->xb_Result;
  369.       return ulen;
  370.     }
  371.  
  372.   /**************************** xfdmaster file **************************/
  373.   case XPKMODE_UPXFD:
  374.     {
  375.       struct xfdMasterBase *xfdMasterBase = (struct xfdMasterBase *) xbuf->xb_SubBase;
  376.       struct xfdBufferInfo *xbi = xbuf->xb_xfd;
  377.  
  378.       xbi->xfdbi_Flags = XFDFF_USERTARGET;
  379.       xbi->xfdbi_UserTargetBuf = buf;
  380.       xbi->xfdbi_UserTargetBufLen = len;
  381.       if((xbuf->xb_Fib.xf_Flags & XPKFLAGS_KEY32) &&
  382.       (xbuf->xb_Flags & XMF_KEY32))
  383.         xbi->xfdbi_Special = &xbuf->xb_PassKey32;
  384.       else if((xbuf->xb_Fib.xf_Flags & XPKFLAGS_KEY16) &&
  385.       (xbuf->xb_Flags & XMF_KEY16))
  386.         xbi->xfdbi_Special = &xbuf->xb_PassKey16;
  387.       else if(xbuf->xb_Fib.xf_Flags & XPKFLAGS_PASSWORD)
  388.         xbi->xfdbi_Special = xbuf->xb_Password;
  389.  
  390.       if(!xfdDecrunchBuffer(xbi))
  391.       {
  392.         switch(xbi->xfdbi_Error)
  393.         {
  394.         case XFDERR_NOMEMORY: xbuf->xb_Result = XPKERR_NOMEM; break;
  395.         case XFDERR_WRONGPASSWORD: case XFDERR_WRONGKEY:
  396.           xbuf->xb_Result = XPKERR_WRONGPW; break;
  397.         case XFDERR_CORRUPTEDDATA: xbuf->xb_Result = XPKERR_CORRUPTPKD; break;
  398.         case XFDERR_BETTERCPU: xbuf->xb_Result = XPKERR_WRONGCPU; break;
  399.         default: xbuf->xb_Result = XPKERR_UNKNOWN; break;
  400.         }
  401.  
  402. #ifdef DEBUG
  403.   DebugRunTime("XpkRead: xfd failed with %ld", xbuf->xb_Result);
  404. #endif
  405.         return xbuf->xb_Result;
  406.       } /* xfdDecrunchBuffer */
  407.  
  408.       xbuf->xb_Fib.xf_CCur = xbuf->xb_InLen;
  409.       xbuf->xb_Fib.xf_UCur = xbuf->xb_Fib.xf_ULen;
  410.       xbuf->xb_Fib.xf_NLen = 0;
  411.       xbuf->xb_Flags |= XMF_EOF;
  412.  
  413. #ifdef DEBUG
  414.   DebugRunTime("XpkRead: xfd returns %ld", xbuf->xb_Fib.xf_ULen);
  415. #endif
  416.       return (LONG) xbuf->xb_Fib.xf_ULen;
  417.     }
  418.     /********************* Unpack unpacked file *******************/
  419.   case XPKMODE_UPUP:
  420.     {
  421.       ULONG leftlen = xbuf->xb_Fib.xf_ULen - xbuf->xb_Fib.xf_CCur;
  422.  
  423.       if(leftlen > len)
  424.     leftlen = len;
  425.       else
  426.         xbuf->xb_Flags |= XMF_EOF;
  427.  
  428.       if(!(MBUG hookread(xbuf, XIO_READ, buf, leftlen)))
  429.         return xbuf->xb_Result;
  430.  
  431.       xbuf->xb_Fib.xf_CCur += leftlen;
  432.       xbuf->xb_Fib.xf_UCur += leftlen;
  433.       xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen -
  434.         xbuf->xb_Fib.xf_UCur, DEFAULTCHUNKSIZE) + XPK_MARGIN;
  435.  
  436.       return (LONG) leftlen;
  437.     }
  438.   }
  439.  
  440.   return xbuf->xb_Result;
  441. }
  442.  
  443. /**************************************************************************
  444.  *
  445.  *   XpkWrite() - write a chunk to a compressed file
  446.  *
  447.  */
  448.  
  449. ASM(LONG) LIBXpkWrite(REG(a0, struct XpkBuffer *xbuf), REG(a1, STRPTR buf),
  450.     REG(d0, ULONG ulen))
  451. {
  452.   struct Library *XpkSubBase = xbuf->xb_SubBase;
  453.   struct XpkSubParams *xpar;
  454.   struct Headers *head = &xbuf->xb_Headers;
  455.   LONG clen, rclen, outbuflen;
  456.   UWORD end[2] = {0,0}; /* last ULONG of buffer, when not longword bounded */
  457.   UBYTE type;
  458.   STRPTR outbuf;
  459.   MBUGDEF
  460.  
  461. #ifdef DEBUG
  462.   DebugRunTime("XpkWrite: buf %08lx, size %ld, uncrunched (%ld/%ld), crunched (%ld/%ld)", buf, ulen,
  463.   xbuf->xb_Fib.xf_UCur, xbuf->xb_Fib.xf_ULen, xbuf->xb_Fib.xf_CCur,xbuf->xb_Fib.xf_CLen);
  464. #endif
  465.  
  466.   if(!xbuf->xb_FirstChunk)
  467.     xbuf->xb_FirstChunk = ulen;
  468.   if(ulen > xbuf->xb_FirstChunk)
  469.     return (xbuf->xb_Result = XPKERR_BADPARAMS);
  470.  
  471.   if(xbuf->xb_Flags & XMF_NOPACK) /* no packing */
  472.   {
  473.     hookwrite(xbuf, XIO_WRITE, buf, ulen);
  474.     xbuf->xb_Fib.xf_UCur += ulen;
  475.     xbuf->xb_Fib.xf_CCur += ulen;
  476.     xbuf->xb_Fib.xf_CLen += ulen;
  477.     xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen - xbuf->xb_Fib.xf_UCur,
  478.       (LONG) xbuf->xb_ChunkSize);
  479.     return xbuf->xb_Result;
  480.   }
  481.  
  482.   /******************* Write the GlobHdr ********************/
  483.   if(!(xbuf->xb_Flags & XMF_GLOBHDR))
  484.   {
  485.     if(!xbuf->xb_Password)
  486.       CopyMem(buf, head->h_Glob.xsh_Initial, Min(16, ulen));
  487.     xbuf->xb_Flags |= XMF_GLOBHDR;
  488.     if(!(MBUG hookwrite(xbuf, XIO_WRITE, &head->h_Glob,
  489.     sizeof(struct XpkStreamHeader))))
  490.       return xbuf->xb_Result;
  491.     xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
  492.   }
  493.  
  494.   /******************* Allocate the buffer *****************/
  495.   outbuflen = ROUNDLONG(ulen + (ulen>>5) + head->h_LocSize) + XPK_MARGIN;
  496.   if(!(outbuf = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, outbuflen)))
  497.     return xbuf->xb_Result;
  498.  
  499.   outbuf += head->h_LocSize;
  500.   /* compress to behind local header. This is needed by mem-out hook! */
  501.  
  502.   if(ulen < xbuf->xb_SubInfo->xi_MinPkInChunk)
  503.     goto copychunk;
  504.  
  505.   /******************* Pack the chunk **********************/
  506.   xpar = &xbuf->xb_PackParam;
  507.   xpar->xsp_InBuf = buf;
  508.   xpar->xsp_InLen = ulen;
  509.   xpar->xsp_OutBuf = outbuf;
  510.   xpar->xsp_OutBufLen = outbuflen - head->h_LocSize;
  511.   xpar->xsp_Number += 1;
  512.   xpar->xsp_Mode = xbuf->xb_PackingMode;
  513.   xpar->xsp_Password = xbuf->xb_Password;
  514.   xpar->xsp_LibVersion = xbuf->xb_SubInfo->xi_LibVersion;
  515.  
  516.   xbuf->xb_Result = XpksPackChunk(xpar);
  517.   xbuf->xb_Flags |= XMF_INITED;
  518.  
  519.   type = XPKCHUNK_PACKED;
  520.   clen = xpar->xsp_OutLen;
  521.  
  522.   if(xbuf->xb_Result == XPKERR_EXPANSION)
  523.   {
  524.     xbuf->xb_Result = 0;
  525. copychunk:
  526.     type = XPKCHUNK_RAW;
  527.     clen = ulen;
  528.     outbuf = buf;
  529.   }
  530.  
  531.   if(xbuf->xb_Result)
  532.     return xbuf->xb_Result;
  533.  
  534.   /******************* Write the chunk **********************/
  535.   head->h_Loc.xch_Word.xchw_Type = type;
  536.   if(head->h_Glob.xsh_Flags & XPKSTREAMF_LONGHEADERS)
  537.   {
  538.     head->h_Loc.xch_Long.xchl_ULen = ulen;
  539.     head->h_Loc.xch_Long.xchl_CLen = clen;
  540.   }
  541.   else
  542.   {
  543.     head->h_Loc.xch_Word.xchw_ULen = (WORD) ulen;
  544.     head->h_Loc.xch_Word.xchw_CLen = (WORD) clen;
  545.   }
  546.  
  547.   if((rclen = clen&3))
  548.   {
  549.     clen -= rclen;
  550.     CopyMem(outbuf+clen, &end, rclen); /* copy the remaining bytes (max 3) */
  551.   }
  552.  
  553.   head->h_Loc.xch_Word.xchw_CChk = cchecksum((ULONG *) outbuf, clen >> 2)
  554.     ^ end[0] ^ end[1];
  555.   /* add the rest bytes to the checksum */
  556.   
  557.   head->h_Loc.xch_Word.xchw_HChk = 0;
  558.   head->h_Loc.xch_Word.xchw_HChk = hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);
  559.  
  560.   if(!(MBUG hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize)))
  561.     return xbuf->xb_Result;
  562.  
  563.   if(!(MBUG hookwrite(xbuf, XIO_WRITE, outbuf, clen)))
  564.     return xbuf->xb_Result;
  565.  
  566.   if(rclen)
  567.   {
  568.     if(!(MBUG hookwrite(xbuf, XIO_WRITE, &end, 4)))
  569.       return xbuf->xb_Result;
  570.     clen += 4;
  571.   }
  572.  
  573.   head->h_Glob.xsh_ULen += ulen;
  574.   
  575.   xbuf->xb_Fib.xf_UCur += ulen;
  576.   xbuf->xb_Fib.xf_CCur += head->h_LocSize + clen;
  577.   xbuf->xb_Fib.xf_CLen = xbuf->xb_Fib.xf_CCur;
  578.   xbuf->xb_Fib.xf_NLen = Min(max(xbuf->xb_InLen, head->h_Glob.xsh_ULen) -
  579.     xbuf->xb_Fib.xf_UCur, (LONG) xbuf->xb_ChunkSize);
  580.  
  581.   return xbuf->xb_Result;
  582. }
  583.  
  584. /**************************************************************************
  585.  *
  586.  *   XpkClose() - finish (de)compressing an XPK file
  587.  *
  588.  */
  589.  
  590. ASM(LONG) LIBXpkClose(REG(a0, struct XpkBuffer *xbuf))
  591. {
  592.   struct Library *XpkSubBase = xbuf->xb_SubBase;
  593.  
  594.   if(!xbuf)
  595.     return 0;
  596.  
  597. #ifdef DEBUG
  598.   if(xbuf->xb_Result)
  599.     DebugError("XpkClose: failed (%ld) before XpkClose", xbuf->xb_Result);
  600. #endif
  601.  
  602.   if(xbuf->xb_Format == XPKMODE_PKSTD)
  603.   {
  604.     struct Headers *head = &xbuf->xb_Headers;
  605.     LONG outlen;
  606.  
  607.     if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_GLOBHDR|XMF_NOPACK))
  608.     {
  609.       hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
  610. #ifdef DEBUG
  611.       if(xbuf->xb_Result) DebugError("XpkClose: failed to write globhdr");
  612. #endif
  613.       xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
  614.     }
  615.     if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_NOPACK))
  616.     {
  617.       /******************* Write final chunk header *****************/
  618.       memset(&head->h_Loc, 0, head->h_LocSize);
  619.       head->h_Loc.xch_Word.xchw_Type = XPKCHUNK_END;
  620.       head->h_Loc.xch_Word.xchw_HChk = 0;
  621.       head->h_Loc.xch_Word.xchw_HChk =
  622.         hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);
  623.  
  624.       hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize);
  625. #ifdef DEBUG
  626.       if(xbuf->xb_Result) DebugError("XpkClose: failed to write lochdr");
  627. #endif
  628.       xbuf->xb_Fib.xf_CCur += head->h_LocSize;
  629.       outlen = xbuf->xb_Fib.xf_CCur;
  630.  
  631.       /********************** Write global header *******************/
  632.       hookwrite(xbuf, XIO_SEEK, NULL, -outlen);
  633. #ifdef DEBUG
  634.       if(xbuf->xb_Result) DebugError("XpkClose: failed to reset output");
  635. #endif
  636.  
  637.       head->h_Glob.xsh_Pack = XPK_COOKIE;
  638.       head->h_Glob.xsh_CLen = outlen - 8;
  639.       head->h_Glob.xsh_HChk = 0;
  640.       head->h_Glob.xsh_HChk =
  641.         hchecksum((STRPTR) &head->h_Glob, sizeof(struct XpkStreamHeader));
  642.  
  643.       hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
  644. #ifdef DEBUG
  645.       if(xbuf->xb_Result) DebugError("XpkClose: failed updating globalhdr");
  646. #endif
  647.  
  648.       hookwrite(xbuf, XIO_SEEK, 0, outlen - sizeof(struct XpkStreamHeader));
  649. #ifdef DEBUG
  650.       if(xbuf->xb_Result) DebugError("XpkClose: failed to SEEK to end of output");
  651. #endif
  652.     }
  653.     xbuf->xb_Fib.xf_CLen = xbuf->xb_Fib.xf_CCur;
  654.     xbuf->xb_Fib.xf_ULen = xbuf->xb_Fib.xf_UCur;
  655.  
  656.     /*************************** Shut down *************************/
  657.     if(xbuf->xb_Flags & XMF_INITED)
  658.       XpksPackFree(&xbuf->xb_PackParam);
  659.   }
  660.   else if(xbuf->xb_Format == XPKMODE_UPSTD && xbuf->xb_Flags & XMF_INITED)
  661.     XpksUnpackFree(&xbuf->xb_PackParam);
  662.  
  663.   if(xbuf->xb_RHook)
  664.   {
  665.     hookread(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
  666. #ifdef DEBUG
  667.     if(xbuf->xb_Result) DebugError("XpkClose: failed read ABORT/FREE");
  668. #endif
  669.   }
  670.  
  671.   if(xbuf->xb_WHook)
  672.   {
  673.     hookwrite(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
  674. #ifdef DEBUG
  675.     if(xbuf->xb_Result) DebugError("XpkClose: failed write ABORT/FREE");
  676. #endif
  677.   }
  678.  
  679.   parsegettags(xbuf);        /* Send information to the user */
  680.  
  681. #ifdef DEBUG
  682.     DebugRunTime("XpkClose: InLen %ld, CLen %ld, ULen %ld, ID %.4s", xbuf->xb_InLen,
  683.     xbuf->xb_Fib.xf_CLen, xbuf->xb_Fib.xf_ULen, &xbuf->xb_Fib.xf_ID);
  684. #endif
  685.  
  686.   return freebufs(xbuf);
  687. }
  688.  
  689. #endif /* XPKMASTER_XPKMASTER_C */
  690.  
  691.